kernel/vtpm: Support vtpm invocation using an external state file#1124
Draft
armenon-rh wants to merge 6 commits into
Draft
kernel/vtpm: Support vtpm invocation using an external state file#1124armenon-rh wants to merge 6 commits into
armenon-rh wants to merge 6 commits into
Conversation
Currently the attestation flow only works against the mock attestation
server. Against the production-ready Trustee KBS (CoCo), attestation
fails immediately because the cryptographic hashes do not match.
The RCAR (Request-Challenge-Attestation-Response) handshake forms the
basis of secret retrieval from KBS. This has 2 parts, negotiation and
attestation. Negotiation phase typically only allows the client to get a
nonce from the KBS, and this nonce will be used in the attestation
request in the subsequent step. For SVSM, the client is SVSM + aproxy.
The current negotiation request:
SVSM sends only version and tee to aproxy. SVSM public key is not sent.
The current negotiation response:
aproxy fetches the challenge nonce from KBS and send it back to SVSM.
The current hashing in svsm:
SVSM does the hashing locally in the kernel by concatenating the raw
bytes of the nonce and the pub_key coordinates, hashing them with
SHA-512.
Report data = sha512(nonce + pub_key_x + pub_key_y).
This is signed by the AMD processor.
The real Trustee KBS does not expect a raw concatenation of bytes hashed
with SHA-512. Instead, the KBS verifier expects the runtime data to be a
JWS-formatted JSON object containing specific parameters, hashed with
SHA-384, see below.
{
"nonce": kbs-nonce,
"additional-evidence": "",
"tee-pubkey": {
"kty": "EC",
"crv": "P-521",
"x": "..."
"y": "..."
}
}
Although the hashing and serializing can be done in SVSM, it is not wise
to add/implement the JSON serializer in the kernel. We would also
require a base64url encoder. Besides, if SVSM constructs the
KBS-specific JSON, SVSM becomes tightly coupled to the specific API
implementation of a single KBS (Trustee).
For those reasons, the job of serialising and hashing should be done by
the aproxy. Because the baremetal SVSM kernel cannot do complex JSON
formatting, serialization, JWS mapping and base64 encoding, SVSM could
not compute this JSON-based hash. As a result the hash SVSM signed in the report
never matches the hash that KBS expected, and the attestation failed.
This commit allows aproxy to have the public key of svsm ready to use
during the negotiation phase itself. By sending SVSM's public key during
negotiation, aproxy can compute the SHA-384 of the constructed JSON first,
and pass it back to SVSM. SVSM can pass that hash to the AMD CPU to be
hardware-signed.
SVSM APROXY Trustee KBS
| | |
| | |
| 1. Negotiation | |
+---------------->| |
| Request | |
|(tee, ver, pk) |2. GET/auth |
| +--------------->|
| | 3. Returns |
| |<---------------+
| | challenge nonce|
| | |
| | |
| | |
| |4. Precomputes |
| | KBS hashing. |
| |a. Constructs runtime_data JSON
| | (with nonce + SVSM key)
| |b. Computes sha-384 of this JSON
| | This is called challenge hash
| | |
| | |
| | |
| 5. Negotiation | |
|<----------------+ |
| Response | |
| | |
| | |
| | |
|6. Requests Hardware Report |
| Passes Challenge hash as |
| REPORT_DATA. AMD CPU signs |
| Challenge Hash| |
| | |
| | |
| | |
| | |
| 7. Attestation | |
+---------------->| |
| Request | |
| Sends TEE report| |
| + SVSM pubkey | |
| | 8. POST/attest |
| +--------------->|
| | -Sends TEE rep |
| | -Sends runtime_|
| | data JSON with|
| | (nonce + pubkey)
| | |
| | |
| | | 9.Verification at KBS
| | | a. Compute sha384 of runtime
| | | data (covers nonce+pubkey)
| | | b. Reads REPORT_DATA from TEE
| | | Report. Contains (challenge Hash)
| | | c. Compares both. Attestation
| | | accepted. Issue attestation token.
v v v
A subsequent commit will move the JSON construction and hashing
responsibility out of the kernel, and put it into the aproxy.
Signed-off-by: Arun Menon <armenon@redhat.com>
Running SVSM against a trustee KBS service to verify the attestation report and get the attestation token back fails with the error "Deserialize SNP Evidence failed" [1] On further inspection, here are a few problems identified with the current attestation flow: 1. The trustee KBS service depends on the virtee sev crate AttestationReport structure [2] and it does not match with the structure of AttestationReport that SVSM sends to aproxy. As a result the deserialization fails. 2. The additional_evidence is not passed in the report at all. 3. Runtime data is hashed using sha512 whereas KBS service expects to use Sha384 hash function. 4. nonce should be stored from the negotiation response, so that it can be sent back in the attestation request. In this commit, we add the official 'sev' crate (from virtee, with snp and serde features enabled) to aproxy's dependencies, and implement a decoupled KBS backend in tools/aproxy. [3] The aproxy KBS backend parses the raw report bytes received from SVSM using sev::firmware::guest::AttestationReport. This completely decouples the SVSM kernel from KBS serialization format requirements. The standard parser utilized by the KBS evidence verifier is used in the aproxy, resolving previous deserialization failures. aproxy backend now constructs the complete, KBS-compliant runtime_data JSON object (which contains the nonce and the tee-pubkey formatted with JWS parameters like alg: 'ECDH-ES+A256KW' and crv: 'P-521'). aproxy serializes this entire JSON object, computes its SHA-384 hash, and returns this combined hash to SVSM as the NegotiationResponse challenge. SVSM then simply hashes this single challenge into its SEV-SNP report. Update the hash function in kernel/src/attest.rs to directly copy the 48 byte challenge into a zero padded 64 byte array. Hashing is actually performed in the aproxy and the hash function used is Sha384 Casting SNP report bytes into sev crate's AttestationReport structure via read_unaligned causes undefined behaviour due to optimized Option enums. Replace unsafe cast with sev::parser::Decoder to safely decode the report byte-by-byte into the correct memory layout. Adding resource_id: Option<String> to KbsProtocol prevents the Protocol enum from implementing Copy. Therefore pattern matching on self.protocol directly inside HttpClient method now borrows self, and that conflicts with subsequently passing self as mutable reference to the backend method calls like negotiation and attestation. Use idiomatic mem::replace pattern to avoid this. Since sev crate introduces std, make clippy --all-features fails. Invoking clippy with CARGO_HACK=1 succeeds. make clippy CARGO_HACK=1 [1] https://github.com/confidential-containers/trustee/blob/main/deps/verifier/src/snp/mod.rs#L351 [2] https://github.com/confidential-containers/trustee/blob/main/deps/verifier/Cargo.toml#L96 [3] https://docs.rs/crate/sev/8.0.0/source/src/firmware/guest/types/snp.rs#255 Signed-off-by: Arun Menon <armenon@redhat.com>
The request from aproxy to KBS, post a successful attestation, could be a secret resource stored on the storage backend or a simple call to the numerous plugins that KBS offers. SVSM intends to use the wrap-key endpoint of KBS to retrieve the unwrapped key to decrypt the vTPM state file. The SecretRequest enum captures these two variants, and can be extended in future. This is added to AttestationRequest from SVSM and the aproxy can hit the KBS wrap-key endpoint immediately post attestation. Signed-off-by: Arun Menon <armenon@redhat.com>
Introduce the fetch_secret helper function in the KBS attestation protocol backend to handle the newly introduced SecretRequest flow. This function allows the user to fetch the secret based on the type of the kbs backend it is stored in. Signed-off-by: Arun Menon <armenon@redhat.com>
SVSM's vTPM could not receive external persistent state on init, nor did it store the KBS key for future state encryption/decryption. Update vtpm_init and TCG TPM backend to accept an optional state buffer and store the KBS secret key in the TcgTpm struct. This stored key will be used for future state decryption on startup. Even though state is passed as a buffer to the vtpm_init() function, it does not come in effect yet, because the tpm reference implementation does not copy platParameter into s_NV buffer in _plat__NVEnable() function. Signed-off-by: Arun Menon <armenon@redhat.com>
Update SVSM guest to read the first sector from the virtio block device to extract the 256-byte wrapped key (wrapped with HSM's public key) from the "SVSMvTPM" header at offset 64. Modify the SVSM attestation driver interface to accept and send this wrap key payload directly to aproxy within the attestation request. Update vTPM state loading process to start reading the encrypted state payload from offset 320. If the guest's block device does not contain a valid SVSMvTPM magic header or wrapped key, abort the initialization to prevent silent boot failures. This is a PoC implementation commit, and is intended to be replaced with the cocoon-fs implementation at a later stage. Signed-off-by: Arun Menon <armenon@redhat.com>
bfeb3d1 to
9af3f2c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add vTPM state file as a parameter to vtpm_init() allowing it to initialize the vTPM with an external state file.
In order to create an external vTPM state file image, that can be attached to svsm as a virtio-blk device, use vtpm-to-svsm-blk
This PR depends on: #1123. Please review only the commits 6cfe74e, 9af3f2c